package framework.remote
{
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;
	import framework.branch;
	import mx.collections.ArrayCollection;
	import mx.rpc.AbstractOperation;
	import mx.rpc.AsyncToken;

	[Wire(initialize="false")]
	public dynamic class CachedService extends Proxy
	{
		public function CachedService(service:Object = null)
		{
			this.service = service;
		}

		public var service:Object;

		private var cache:Object = {};

		public function refresh():AsyncToken
		{
			var tokens:Array = [];
			for (var s:String in cache)
			{
				tokens.push(RemoteCollection(cache[s]).refreshRemote());
			}
			return branch.apply(this, tokens);
		}

		public function removeAll():void
		{
			for (var s:String in cache)
			{
				ArrayCollection(cache[s]).removeAll();
			}
			cache = {};
		}

		override flash_proxy function callProperty(name:*, ... args:Array):*
		{
			return callMethod(name, args);
		}

		public function callMethod(name:*, args:Array):*
		{
			var s:String = makeCollectionName(name, args);
			var r:RemoteCollection = cache[s];
			if (!r)
			{
				var f:Function;
				if (service[name] is Function)
				{
					f = service[name] as Function;
				}
				else if (service[name] is AbstractOperation)
				{
					f = AbstractOperation(service[name]).send;
				}
				else
				{
					throw new Error(name + " is neither function nor AbstractOperation");
				}
				r = new RemoteCollection(f, args);
				cache[s] = r;
				r.refreshRemote();
			}
			return r;
		}

		private function makeCollectionName(name:*, args:Array):String
		{
			var s:String = String(name);
			for each (var obj:Object in args)
			{
				if ("id" in args)
				{
					s += "-" + obj.id;
				}
				else
				{
					s += "-" + obj;
				}
			}
			return s;
		}
	}
}